import { HttpEvent, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { map, Observable, Subject, tap } from 'rxjs';

import { BaseHttpService } from '@core/base/base-http.service';

import { Metadata } from './local.model';

@Injectable({ providedIn: 'root' })
export class LocalService {
  private baseFileUrl = '/oss/v1/files';
  private baseMetadataUrl = '/oss/v1/metadatas';

  private upload$ = new Subject<Metadata>();
  private remove$ = new Subject<Metadata>();

  constructor(private http: BaseHttpService) {}

  public get onUpload(): Observable<Metadata> {
    return this.upload$.asObservable();
  }

  public get onRemove(): Observable<Metadata> {
    return this.remove$.asObservable();
  }

  uploadEvent(formData: FormData): Observable<HttpEvent<any>> {
    return this.http
      .post<any>(`${this.baseFileUrl}/upload`, formData, null, {
        observe: 'events',
        reportProgress: true
      })
      .pipe(
        tap(e => {
          if (e instanceof HttpResponse) {
            this.upload$.next(new Metadata(e.body));
          }
        })
      );
  }

  upload(formData: FormData): Observable<Metadata> {
    return this.http.post<Metadata>(`${this.baseFileUrl}/upload/`, formData).pipe(
      map(e => new Metadata(e)),
      tap(e => {
        this.upload$.next(e);
      })
    );
  }

  download(metadataId: string): Observable<Blob> {
    return this.http.get(`${this.baseFileUrl}/download/${metadataId}`, null, { responseType: 'blob' });
  }

  downloads(metadataIds: string[]): Observable<Blob> {
    const queryParams = { metadataIds: metadataIds };
    return this.http.get(`${this.baseFileUrl}/downloads/`, queryParams, { responseType: 'blob' });
  }

  delete(metadataId: string): Observable<any> {
    const url = `${this.baseFileUrl}/${metadataId}`;
    return this.http.delete(url).pipe(
      tap(e => {
        this.remove$.next(new Metadata(e));
      })
    );
  }

  public getMetadataById(id: string): Observable<Metadata> {
    return this.http.get<Metadata>(`${this.baseMetadataUrl}/${id}`).pipe(map(data => new Metadata(data)));
  }

  public getMetadataByIds(ids: string[]): Observable<Metadata[]> {
    const queryParams = { ids: ids };
    return this.http
      .get<Metadata[]>(`${this.baseMetadataUrl}/ids`, queryParams)
      .pipe(map(data => data.map(e => new Metadata(e))));
  }

  public updateMetadataById(id: string, name: string): Observable<Metadata> {
    const queryParams = { name: name };
    return this.http.get<Metadata>(`${this.baseMetadataUrl}/${id}`, queryParams).pipe(map(e => new Metadata(e)));
  }
}
